package org.codetranslators.testing;

import java.util.Vector;
import java.io.File;
import java.io.FileWriter;

import org.codetranslators.common.ControlFlowGraph;
import org.codetranslators.common.Temp;
import org.codetranslators.common.optimization.OptimizationContext;
import org.codetranslators.compiler.intermrep.AssemblyInstruction;
import org.codetranslators.compiler.intermrep.CJump;
import org.codetranslators.compiler.intermrep.Call;
import org.codetranslators.compiler.intermrep.Jump;
import org.codetranslators.compiler.intermrep.LabelInstr;
import org.codetranslators.compiler.intermrep.Operation;

public class TestSSA {

	public static void main(String[] args){
		
		TestSSA testSSA = new TestSSA();
		Vector instList = testSSA.getInstructionsListForDeadCodeTest();
		//Vector instList = testSSA.getInstructionsListForSSATest();
		//testSSA.writeInstructionsToFile(new File("C:\\SSAInputTest.s"), instList);
		testSSA.writeInstructionsToFile(new File("C:\\DeadCodeTest.s"), instList);
		
		ControlFlowGraph flowGraph = new ControlFlowGraph(instList, false);
		System.out.println("%%%%%%%%%%%CONTROL FLOW GRAPH INPUT: ");
		
		OptimizationContext optimizationContext = new OptimizationContext(flowGraph);
		optimizationContext.setSSAMethod();
		flowGraph = optimizationContext.getOptimizedFlowGraph();
		
		System.out.println("%%%%%%%%%%%CONTROL FLOW GRAPH AFTER OPTIMIZATION USING SSA FORM ");
		flowGraph.displayFlowGraph();
	}
	
	private Vector getInstructionsListForSSATest(){
		Vector instList = new Vector();
		
		// Create the temporaries
		Temp aTemp = new Temp();
		Temp bTemp = new Temp();
		Temp cTemp = new Temp();
		Temp dTemp = new Temp();
		Temp yTemp = new Temp();
		Temp zTemp = new Temp();
		Temp iTemp = new Temp();
		
		// Statement 0
		String lbl0 = "L0";
		String lblStr0 = lbl0 + ":" + "\n";
		LabelInstr stm0 = new LabelInstr(lblStr0, lbl0);
		
		// Statement 1
		Vector destList1 = new Vector();
		destList1.add(iTemp);
		Operation stm1 = new Operation(destList1, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(1), null);
		
		// Statement 2
		Vector srcList1 = new Vector();
		srcList1.add(iTemp);
		String lbl1 = "L1";
		String lbl2 = "L2";
		CJump stm2 = new CJump(srcList1, lbl1, lbl2, CJump.GT, new Integer(100));
		
		// Statement 3
		String lblStr1 = lbl2 + ":" + "\n";
		LabelInstr stm3 = new LabelInstr(lblStr1, lbl2);
		
		// Statement 4
		Vector destList2 = new Vector();
		destList2.add(aTemp);
		Operation stm4 = new Operation(destList2, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(21), null); 
		
		// Statement 5
		Vector destList3 = new Vector();
		destList3.add(cTemp);
		Operation stm5 = new Operation(destList3, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(45), null); 
		
		// Statement 6
		Vector srcList2 = new Vector();
		srcList2.add(aTemp);
		srcList2.add(cTemp);
		String lbl3 = "L3";
		String lbl4 = "L4";
		CJump stm6 = new CJump(srcList2, lbl3, lbl4, CJump.GT, null);
		
		// Statement 7
		String lblStr2 = lbl4 + ":" + "\n";
		LabelInstr stm7 = new LabelInstr(lblStr2, lbl4);
		
		// Statement 8
		Vector destList4 = new Vector();
		destList4.add(bTemp);
		Operation stm8 = new Operation(destList4, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(47), null); 
		
		// Statement 9
		Vector destList5 = new Vector();
		destList5.add(cTemp);

		Vector srcListWhatever1 = new Vector();
		srcListWhatever1.addElement(aTemp);
		Operation stm9 = new Operation(destList5, srcListWhatever1, Operation.ADD, new Integer(58), null);
		
		//Operation stm9 = new Operation(destList5, null,Operation.LOAD_IMMEDIATE_VALUE,
		//		 new Integer(58), null); 
		
		// Statement 10
		Vector destList6 = new Vector();
		destList6.add(dTemp);
		Operation stm10 = new Operation(destList6, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(17), null);
		
		// Statement 11
		String lbl5 = "L5";
		String jmpStr = "	j " + lbl5 + "\n";
		Jump stm11 = new Jump(jmpStr, lbl5);
		
		// Statement 12
		String lblStr3 = lbl5 + ":" + "\n";
		LabelInstr stm12 = new LabelInstr(lblStr3, lbl5);
		
		// Statement 13
		Vector destList7 = new Vector();
		destList7.addElement(yTemp);
		Vector srcList3 = new Vector();
		srcList3.addElement(aTemp);
		srcList3.addElement(bTemp);
		Operation stm13 = new Operation(destList7, srcList3, Operation.ADD, null, null);
		
		// Statement 14
		Vector destList8 = new Vector();
		destList8.addElement(zTemp);
		Vector srcList4 = new Vector();
		srcList4.addElement(cTemp);
		srcList4.addElement(dTemp);
		Operation stm14 = new Operation(destList8, srcList4, Operation.ADD, null, null);
		
		// Statement 15
		Vector destList9 = new Vector();
		destList9.addElement(iTemp);
		Vector srcList5 = new Vector();
		srcList5.addElement(iTemp);
		Operation stm15 = new Operation(destList9, srcList5, Operation.ADD, new Integer(1), null);
		
		// Statement 16
		Vector srcList6 = new Vector();
		srcList6.add(iTemp);
		CJump stm16 = new CJump(srcList6, lbl2, lbl1, CJump.LT, new Integer(100));
		
		// Statement 17
		String jmpStr1 = "	j " + lbl2 + "\n";
		Jump stm17 = new Jump(jmpStr1, lbl2);
		
		// Statement 18
		String lblStr4 = lbl3 + ":" + "\n";
		LabelInstr stm18 = new LabelInstr(lblStr4, lbl3);
		
		// Statement 19
		Vector destList10 = new Vector();
		destList10.add(aTemp);
		Operation stm19 = new Operation(destList10, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(11), null); 
		
		// Statement 20
		Vector destList11 = new Vector();
		destList11.add(dTemp);
		Operation stm20 = new Operation(destList11, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(97), null); 
		
		// Statement 21
		Vector srcList7 = new Vector();
		srcList7.add(aTemp);
		srcList7.add(dTemp);
		String lbl6 = "L6";
		String lbl7 = "L7";
		CJump stm21 = new CJump(srcList7, lbl7, lbl6, CJump.GT, null);
		
		// Statement 22
		String lblStr5 = lbl6 + ":" + "\n";
		LabelInstr stm22 = new LabelInstr(lblStr5, lbl6);
		
		// Statement 23
		Vector destList12 = new Vector();
		destList12.add(dTemp);
		Operation stm23 = new Operation(destList12, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(2), null); 
		
		// Statement 24
		String lbl8 = "L8";
		String jmpStr2 = "	j " + lbl8 + "\n";
		Jump stm24 = new Jump(jmpStr2, lbl8);
		
		// Statement 25
		String lblStr6 = lbl8 + ":" + "\n";
		LabelInstr stm25 = new LabelInstr(lblStr6, lbl8);
		
		// Statement 26
		Vector destList13 = new Vector();
		destList13.add(bTemp);
		Operation stm26 = new Operation(destList13, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(72), null); 
		
		// Statement 27
		String jmpStr3 = "	j " + lbl5 + "\n";
		Jump stm27 = new Jump(jmpStr3, lbl5);
		
		// Statement 28
		String lblStr7 = lbl7 + ":" + "\n";
		LabelInstr stm28 = new LabelInstr(lblStr7, lbl7);
		
		// Statement 29
		Vector destList14 = new Vector();
		destList14.add(cTemp);
		
		Vector srcListWhatever2 = new Vector();
		srcListWhatever2.addElement(aTemp);
		Operation stm29 = new Operation(destList14, srcListWhatever2, Operation.ADD, new Integer(44), null);
		
		//Operation stm29 = new Operation(destList14, null,Operation.LOAD_IMMEDIATE_VALUE,
		//		 new Integer(44), null); 
		
		// Statement 30
		Jump stm30 = new Jump(jmpStr2, lbl8);
		
		// Statement 31
		String lblStr8 = lbl1 + ":" + "\n";
		LabelInstr stm31 = new LabelInstr(lblStr8, lbl1);
		
		// Add all the statements to the list of statements and return it
		instList.addElement(stm0);
		instList.addElement(stm1);
		instList.addElement(stm2);
		instList.addElement(stm3);
		instList.addElement(stm4);
		instList.addElement(stm5);
		instList.addElement(stm6);
		instList.addElement(stm7);
		instList.addElement(stm8);
		instList.addElement(stm9);
		instList.addElement(stm10);
		instList.addElement(stm11);
		instList.addElement(stm18);
		instList.addElement(stm19);
		instList.addElement(stm20);
		instList.addElement(stm21);
		instList.addElement(stm22);
		instList.addElement(stm23);
		instList.addElement(stm24);
		instList.addElement(stm25);
		instList.addElement(stm26);
		instList.addElement(stm27);
		instList.addElement(stm28);
		instList.addElement(stm29);
		instList.addElement(stm30);
		
		instList.addElement(stm12);
		instList.addElement(stm13);
		instList.addElement(stm14);
		instList.addElement(stm15);
		instList.addElement(stm16);
		//instList.addElement(stm17);
		
		instList.addElement(stm31);
		
		
		return instList;
				
		
	}
	
	private Vector getInstructionsListForDeadCodeTest(){
		Vector instList = new Vector();
		
		// Create the temporaries
		Temp t0Temp = new Temp();
		Temp t1Temp = new Temp();
		Temp t2Temp = new Temp();
		Temp t3Temp = new Temp();
		Temp t4Temp = new Temp();
		Temp t5Temp = new Temp();
		Temp t6Temp = new Temp();

		// BLOCK 0 (Start block)
		// Statement 0
		String lbl0 = "L0";
		String lblStr0 = lbl0 + ":" + "\n";
		LabelInstr stm0 = new LabelInstr(lblStr0, lbl0);
		
		Vector destList1 = new Vector();
		destList1.add(t0Temp);
		Operation stm1 = new Operation(destList1, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(1), null);
		
		Vector srcList1 = new Vector();
		srcList1.add(t0Temp);
		String lbl1 = "L1";
		String lbl12 = "L12";
		CJump stm2 = new CJump(srcList1, lbl12, lbl1, CJump.GT, new Integer(100));
		
		// BLOCK L1
		// Statement 4
		String lblStr1 = lbl1 + ":" + "\n";
		LabelInstr stm3 = new LabelInstr(lblStr1, lbl1);
		
		Vector destList2 = new Vector();
		destList2.add(t1Temp);
		Operation stm4 = new Operation(destList2, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(3), null); 
		
		// Statement 5
		Vector destList3 = new Vector();
		destList3.add(t2Temp);
		Operation stm5 = new Operation(destList3, null,Operation.LOAD_IMMEDIATE_VALUE,
				 new Integer(3), null); 
		
		// Statement 6
		Vector srcList2 = new Vector();
		srcList2.add(t1Temp);
		srcList2.add(t2Temp);
		String lbl2 = "L2";
		String lbl10 = "L10";
		CJump stm6 = new CJump(srcList2, lbl10, lbl2, CJump.GT, null);
		
		// BLOCK L2
		// Statement 7
		String lblStr2 = lbl2 + ":" + "\n";
		LabelInstr stm7 = new LabelInstr(lblStr2, lbl2);
		
		// Statement 8
		Vector destList5 = new Vector();
		destList5.add(t2Temp);
		Vector srcList3 = new Vector();
		srcList3.addElement(t1Temp);
		Operation stm8 = new Operation(destList5, srcList3, Operation.ADD, new Integer(58), null);
		
		// Statement 9
		Vector destList6 = new Vector();
		Vector srcList4 = new Vector();
		destList6.add(t0Temp);
		srcList4.add(t1Temp);
		srcList4.add(t0Temp);
		Operation stm9 = new Operation(destList6, srcList4, Operation.MUL, null, null);
		
		// Statement 10
		Vector srcList5 = new Vector();
		srcList5.add(t0Temp);
		srcList5.add(t2Temp);
		String lbl3 = "L3";
		String lbl4 = "L4";
		CJump stm10 = new CJump(srcList5, lbl4, lbl3, CJump.LT, null);
		
		// BLOCK L3
		String lblStr3 = lbl3 + ":" + "\n";
		LabelInstr stm11 = new LabelInstr(lblStr3, lbl3);
		
		Vector destList7 = new Vector();
		Vector srcList6 = new Vector();
		srcList6.add(t1Temp);
		srcList6.add(t2Temp);
		destList7.add(t2Temp);
		Operation stm12 = new Operation(destList7, srcList6, Operation.MINUS, null, null);
		
		Vector destList8 = new Vector();
		Vector srcList7 = new Vector();
		srcList7.add(t2Temp);
		destList8.add(t3Temp);
		Operation stm13 = new Operation(destList8, srcList7, Operation.MOVE_TEMP_TO_TEMP, null, null);
		
		Vector destList9 = new Vector();
		Vector srcList8 = new Vector();
		srcList8.add(t3Temp);
		destList9.add(t0Temp);
		Operation stm14 = new Operation(destList9, srcList8, Operation.MOVE_TEMP_TO_TEMP, null, null);
		
		Vector destList10 = new Vector();
		Vector srcList9 = new Vector();
		srcList9.add(t1Temp);
		destList10.add(t2Temp);
		Operation stm15 = new Operation(destList10, srcList9, Operation.MOVE_TEMP_TO_TEMP, null, null);
		
		Vector srcList10 = new Vector();
		srcList10.add(t3Temp);
		srcList10.add(t2Temp);
		String lbl5 = "L5";
		String lbl7 = "L7";
		CJump stm16 = new CJump(srcList10, lbl7, lbl5, CJump.GT, null);
		
		// Block L5
		String lblStr5 = lbl5 + ":" + "\n";
		LabelInstr stm17 = new LabelInstr(lblStr5, lbl5);
		
		Vector destList11 = new Vector();
		Vector srcList11 = new Vector();
		srcList11.add(t0Temp);
		destList11.add(t5Temp);
		Operation stm18 = new Operation(destList11, srcList11, Operation.MINUS, new Integer(3), null);
		
		Vector destList12 = new Vector();
		Vector srcList12 = new Vector();
		srcList12.add(t0Temp);
		destList12.add(t6Temp);
		Operation stm19 = new Operation(destList12, srcList12, Operation.MINUS, new Integer(7), null);
		
		String lbl8 = "L8";
		String jmpStr1 = "	j " + lbl8 + "\n";
		Jump stm20 = new Jump(jmpStr1, lbl8);
		
		// Block L7
		String lblStr7 = lbl7 + ":" + "\n";
		LabelInstr stm21 = new LabelInstr(lblStr7, lbl7);
		
		Vector destList13 = new Vector();
		Vector srcList13 = new Vector();
		srcList13.add(t1Temp);
		destList13.add(t4Temp);
		Operation stm22 = new Operation(destList13, srcList13, Operation.MOVE_TEMP_TO_TEMP, null, null);
		
		Call stm23 = new Call("foo", "jal foo\n");
		
		Jump stm24 = new Jump(jmpStr1, lbl8);
		
		// Block L8
		String lblStr8 = lbl8 + ":" + "\n";
		LabelInstr stm25 = new LabelInstr(lblStr8, lbl8);

		Vector destList14 = new Vector();
		destList14.add(t0Temp);
		Vector srcList14 = new Vector();
		srcList14.addElement(t2Temp);
		srcList14.addElement(t3Temp);
		Operation stm26 = new Operation(destList14, srcList14, Operation.ADD, null, null);
		
		Vector destList15 = new Vector();
		destList15.add(t0Temp);
		Vector srcList15 = new Vector();
		srcList15.addElement(t0Temp);
		Operation stm27 = new Operation(destList15, srcList15, Operation.MINUS, new Integer(5), null);
		
		String lbl9 = "L9";
		String jmpStr2 = "	j " + lbl9 + "\n";
		Jump stm28 = new Jump(jmpStr2, lbl9);
		
		// Block 9
		String lblStr9 = lbl9 + ":" + "\n";
		LabelInstr stm29 = new LabelInstr(lblStr9, lbl9);
		
		Vector destList16 = new Vector();
		destList16.add(t0Temp);
		Vector srcList16 = new Vector();
		srcList16.addElement(t2Temp);
		srcList16.addElement(t1Temp);
		Operation stm30 = new Operation(destList16, srcList16, Operation.MUL, null, null);
		
		Vector destList17 = new Vector();
		destList17.add(t3Temp);
		Vector srcList17 = new Vector();
		srcList17.addElement(t3Temp);
		Operation stm31 = new Operation(destList17, srcList17, Operation.ADD, new Integer(6), null);
		
		Vector srcList18 = new Vector();
		srcList18.add(t0Temp);
		CJump stm32 = new CJump(srcList18, lbl1, lbl12, CJump.GT, new Integer(44));  
		
		// Block 10
		String lblStr10 = lbl10 + ":" + "\n";
		LabelInstr stm33 = new LabelInstr(lblStr10, lbl10);
		
		Vector destList18 = new Vector();
		destList18.add(t1Temp);
		Vector srcList19 = new Vector();
		srcList19.addElement(t2Temp);
		Operation stm34 = new Operation(destList18, srcList19, Operation.ADD, new Integer(4), null);
		
		Vector destList19 = new Vector();
		destList19.add(t2Temp);
		Vector srcList20 = new Vector();
		srcList20.addElement(t1Temp);
		Operation stm35 = new Operation(destList19, srcList20, Operation.MINUS, new Integer(3), null);
		
		Vector destList20 = new Vector();
		destList20.add(t2Temp);
		Vector srcList21 = new Vector();
		srcList21.addElement(t2Temp);
		Operation stm36 = new Operation(destList20, srcList21, Operation.MUL, new Integer(2), null);
		
		Vector srcList22 = new Vector();
		srcList22.add(t1Temp);
		srcList22.add(t2Temp);
		String lbl6 = "L6";
		String lbl11 = "L11";
		CJump stm37 = new CJump(srcList22, lbl6, lbl11, CJump.LT, null);
		
		// Block 11
		String lblStr11 = lbl11 + ":" + "\n";
		LabelInstr stm38 = new LabelInstr(lblStr11, lbl11);
		
		Vector destList21 = new Vector();
		destList21.add(t3Temp);
		Vector srcList23 = new Vector();
		srcList23.addElement(t3Temp);
		Operation stm39 = new Operation(destList21, srcList23, Operation.ADD, new Integer(3), null);
		
		Jump stm40 = new Jump(jmpStr2, lbl9);
		
		// Block 4
		String lblStr4 = lbl4 + ":" + "\n";
		LabelInstr stm41 = new LabelInstr(lblStr4, lbl4);
		
		Vector destList22 = new Vector();
		destList22.add(t4Temp);
		Vector srcList24 = new Vector();
		srcList24.addElement(t2Temp);
		srcList24.addElement(t3Temp);
		Operation stm42 = new Operation(destList22, srcList24, Operation.MINUS, new Integer(3), null);
		
		String jmpStr3 = "	j " + lbl6 + "\n";
		Jump stm43 = new Jump(jmpStr3, lbl6);
		
		// Block 6
		String lblStr6 = lbl6 + ":" + "\n";
		LabelInstr stm44 = new LabelInstr(lblStr6, lbl6);
		
		Vector destList23 = new Vector();
		destList23.add(t5Temp);
		Vector srcList25 = new Vector();
		srcList25.addElement(t0Temp);
		srcList25.addElement(t4Temp);
		Operation stm45 = new Operation(destList23, srcList25, Operation.ADD, null, null);
		
		Vector destList24 = new Vector();
		destList24.add(t4Temp);
		Vector srcList26 = new Vector();
		srcList26.addElement(t5Temp);
		srcList26.addElement(t4Temp);
		Operation stm46 = new Operation(destList24, srcList26, Operation.MUL, null, null);
		
		Vector destList25 = new Vector();
		destList25.add(t5Temp);
		Vector srcList27 = new Vector();
		srcList27.addElement(t5Temp);
		srcList27.addElement(t4Temp);
		Operation stm47 = new Operation(destList25, srcList27, Operation.MINUS, null, null);
		
		String jmpStr7 = "	j " + lbl7 + "\n";
		Jump stm48 = new Jump(jmpStr7, lbl7);
		
		// BLOCK L12: (End block)
		// Statement 3
		String lblStr12 = lbl12 + ":" + "\n";
		LabelInstr stm49 = new LabelInstr(lblStr12, lbl12);
		
		// Add all the statements to the list of statements and return it
		instList.addElement(stm0);
		instList.addElement(stm1);
		instList.addElement(stm2);
		instList.addElement(stm3);
		instList.addElement(stm4);
		instList.addElement(stm5);
		instList.addElement(stm6);
		instList.addElement(stm7);
		instList.addElement(stm8);
		instList.addElement(stm9);
		instList.addElement(stm10);
		instList.addElement(stm11);
		instList.addElement(stm12);
		instList.addElement(stm13);
		instList.addElement(stm14);
		instList.addElement(stm15);
		instList.addElement(stm16);
		instList.addElement(stm17);
		instList.addElement(stm18);
		instList.addElement(stm19);
		instList.addElement(stm20);
		instList.addElement(stm21);
		instList.addElement(stm22);
		instList.addElement(stm23);
		instList.addElement(stm24);
		instList.addElement(stm25);
		instList.addElement(stm26);
		instList.addElement(stm27);
		instList.addElement(stm28);
		instList.addElement(stm29);
		instList.addElement(stm30);
		instList.addElement(stm31);
		instList.addElement(stm32);
		instList.addElement(stm33);
		instList.addElement(stm34);
		instList.addElement(stm35);
		instList.addElement(stm36);
		instList.addElement(stm37);
		instList.addElement(stm38);
		instList.addElement(stm39);
		instList.addElement(stm40);
		instList.addElement(stm41);
		instList.addElement(stm42);
		instList.addElement(stm43);
		instList.addElement(stm44);
		instList.addElement(stm45);
		instList.addElement(stm46);
		instList.addElement(stm47);
		instList.addElement(stm48);
		instList.addElement(stm49);
		
		return instList;
	}
	
	
	private void writeInstructionsToFile(File outFile, Vector instList)
	  {
		  try
		  {
			  FileWriter fileWriter = new FileWriter(outFile);
			  int instNum = instList.size();
			  for(int i = 0; i < instNum; i++)
			  {
				  AssemblyInstruction instr = (AssemblyInstruction) instList.elementAt(i);
				  String linenum = "" + i + ") "; 
				  String str = linenum + instr.getAssemCode(false);
				  fileWriter.write(str);
			  }
			  fileWriter.flush();
			  fileWriter.close();
		  }
		  catch(Exception e)
		  {
			  e.printStackTrace();
		  }
	  }
}
